package com.zyg.seckill.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.zyg.common.entity.TbPayLog;
import com.zyg.seckill.client.UserClient;
import com.zyg.seckill.dao.TbSeckillGoodsMapper;
import com.zyg.seckill.entity.SeckillStatus;
import com.zyg.seckill.entity.TbSeckillGoods;
import com.zyg.seckill.entity.TbSeckillOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;

@Component
public class MultiThreadingCreateOrder {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private TbSeckillGoodsMapper goodsMapper;
    @Autowired
    private UserClient userClient;


     //功能: 1. 异步下单
    @Async
    public TbSeckillOrder syncCreateOrder() {
        //第一阶段：为了保证秒杀用户的有序性
        // 到当前参与秒杀的用户信息-字符串
        String seckillGoodsString = redisTemplate.boundListOps("seckillGoodsQueue").rightPop();

        // 将用户转换为对象
        SeckillStatus seckillStatus = JSON.parseObject(seckillGoodsString, SeckillStatus.class);

        System.out.println("seckillStatus = " + seckillStatus);
        //第二阶段：为了避免重复超卖
        //避免重复超卖
        String s = redisTemplate.boundListOps("SeckillGoodsCountList_" + seckillStatus.getSecKillId()).rightPop();
        System.out.println("s = " + s);

        // 如果在队列中没有数据，就证明此商品己经卖完
        if(s == null){
            clearQueue(seckillStatus.getUsername());
            return null;
        }

        //第三阶段：构造订单对象
        //查询当前秒杀商品是否存在
        BoundHashOperations<String, String, String> operations = redisTemplate.boundHashOps("seckillGoods_" + seckillStatus.getTime());
        String secKillStr = operations.get(seckillStatus.getSecKillId() + "");
        TbSeckillGoods seckillGoods = JSON.parseObject(secKillStr, TbSeckillGoods.class);
        System.out.println("seckillGoods = " + seckillGoods);
        //判断秒杀商品是否存在，如果不存在就抛出异常！
        if(seckillGoods == null || seckillGoods.getStockCount() == 0){
            throw new RuntimeException("商品己售罄");
        }

        // 构造订单对象
        TbSeckillOrder seckillOrder = new TbSeckillOrder();
        seckillOrder.setUserId(seckillStatus.getUsername());
        seckillOrder.setId(IdUtil.createSnowflake(0,1).nextId());
        seckillOrder.setMoney(new BigDecimal(seckillGoods.getCostPrice().doubleValue() * 100));
        seckillOrder.setStatus("0");        //代表未支付
        seckillOrder.setSeckillId(seckillGoods.getId());
        seckillOrder.setCreateTime(new Date());
        seckillOrder.setReceiver("小缘");
        // 将订单保存到redis中
        redisTemplate.boundHashOps("seckillOrder").put(seckillStatus.getUsername(),JSON.toJSONString(seckillOrder));;

        //第四阶段：修改商品的库存（精准扣减）
        //精准扣减库存
        Long stockCount = redisTemplate.boundHashOps("SeckillGoodsCount").increment(seckillGoods.getId()+"", -1);
        seckillGoods.setStockCount(new Integer(stockCount + ""));
        //如果是小于或等于0，证明此商品已卖完
        if(stockCount <= 0){
            //1.10.1 修改回数据库中
            goodsMapper.updateById(seckillGoods);
            //1.10.2 从redis中删除此商品
            redisTemplate.boundHashOps("seckillGoods_" + seckillStatus.getTime()).delete(seckillGoods.getId()+"");
        }else{  //1.10.3 如果存在此商品就修改库存到redis中
            redisTemplate.boundHashOps("seckillGoods_" + seckillStatus.getTime()).put(seckillGoods.getId()+"",JSON.toJSONString(seckillGoods));
        }

        //第五阶段：修改秒杀用户信息
        //修改秒杀用户的其它信息
        seckillStatus.setOrderId(IdUtil.createSnowflake(0,1).nextId());
        seckillStatus.setStatus(2);                                         //排队完成，等待支付
        seckillStatus.setMoney(seckillGoods.getCostPrice().floatValue());   //秒杀商品的单价


        //将用户信息备份到redis中，因为右侧弹出此用户后，就没有此用户的相关信息了
        redisTemplate.boundHashOps("UserQueueStatus").put(seckillStatus.getUsername(),JSON.toJSONString(seckillStatus));


        //保存支付日志
        savePayLog(seckillOrder);

        // 将登录名放到redis中
        redisTemplate.opsForValue().set(seckillOrder.getId() + "",seckillStatus.getUsername());

        return seckillOrder;
    }


     // 功能: 2. 清空用户信息

    private void clearQueue(String username) {
        //2.1 删除保证用户排队的有序性的数据
        redisTemplate.boundHashOps("seckillGoodsQueue").delete(username);
        //2.2 删除当前用户的信息
        redisTemplate.boundHashOps("UserQueueStatus").delete(username);
    }

    private void savePayLog(TbSeckillOrder order) {
        // 定义一个TbPaylog对象
        TbPayLog payLog = new TbPayLog();
        payLog.setOutTradeNo(IdUtil.createSnowflake(0,1).nextIdStr());
        // 设置秒杀订单id
        payLog.setOrderList(order.getId() + "");

        payLog.setCreateTime(new Date());
        payLog.setPayType("2");
        payLog.setTotalFee(order.getMoney().longValue());
        payLog.setTradeState("0");      //0: 未支付 1：己支付
        payLog.setUserId(order.getUserId());

        // payLogMapper.insert(payLog);
        userClient.add(payLog);
        //将支付日志添加redis中
        redisTemplate.opsForValue().set("seckill_paylog_" + order.getUserId(),JSON.toJSONString(payLog));
    }
}